package gurulab.merlin.bus;

import gurulab.maya.common.PhoneAddress;
import gurulab.merlin.core.CantHandException;
import gurulab.merlin.core.envelope.Envelope;
import gurulab.merlin.core.envelope.EnvelopeHandler;
import gurulab.merlin.core.router.Route;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;

/**
 *
 * @author Cesar Obach-Renner, cesar AT gurulab.org
 * @version 1.0
 */
public class EnvelopeBus implements EnvelopeHandler{
    private Map outboundQueues = new HashMap ();
    private Map inboundQueues = new HashMap ();
    private Map handlers = new HashMap ();
    static Logger logger = Logger.getLogger (EnvelopeBus.class);
    
    /**
     * Instancia el MsgBus registrando un consumidor/procesador de la capa <i>layerId </i>
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */
    public EnvelopeBus () {
    }
    
    /**
     *
     * @param handler
     * @param route
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @throws gurulab.merlin.bus.RouteAlreadyHandledException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */
    public void connectHandler (EnvelopeHandler handler, Route route) throws MessagingInfrastructureException, RouteAlreadyHandledException {
        try {
            
            if (inboundQueues.containsKey (route)) { throw new RouteAlreadyHandledException ("route:" + route); }
            
            handlers.put (handler, route);
            JMSQueue queue = new JMSQueue (route.getNode(), handler);
            inboundQueues.put (route, queue);
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        }
    }
    
    /**
     *
     * @param handler
     * @throws gurulab.merlin.bus.HandlerNotFoundException
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void disconnectHandler (EnvelopeHandler handler) throws HandlerNotFoundException, MessagingInfrastructureException {
        Route route;
        UVQueue queue;
        
        if ((route = (Route) handlers.remove (handler)) == null) { throw new HandlerNotFoundException (""); }
        queue = (UVQueue) inboundQueues.remove (route);
        try {
            queue.finalize ();
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        } finally {
            
        }
    }
    
    /**
     *
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void start () throws MessagingInfrastructureException {
        try {
            for (Iterator iter = inboundQueues.values ().iterator (); iter.hasNext ();) {
                ((UVQueue) iter.next ()).start ();
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        } finally {
            
        }
    }
    
    /**
     *
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void stop () throws MessagingInfrastructureException {
        try {
            for (Iterator iter = inboundQueues.values ().iterator (); iter.hasNext ();) {
                ((JMSQueue) iter.next ()).stop ();
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        } finally {
            
        }
        
    }
    
    /**
     *
     * @param route
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void stop (Route route) throws MessagingInfrastructureException {
        try {
            String routeName = route.toString ().trim ();
            JMSQueue jmsQueue = null;
            for (Iterator iter = inboundQueues.values ().iterator (); iter.hasNext ();) {
                jmsQueue = (JMSQueue) iter.next ();
                logger.info ("stoping queue connection..."+routeName);
                if (routeName.equalsIgnoreCase (jmsQueue.queueName)) {
                    jmsQueue.queueConnection.stop ();
                }
                logger.info ("queue connection "+routeName+" stoped");
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        } finally {
            
        }
    }
    
    /**
     *
     * @param route
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void start (Route route) throws MessagingInfrastructureException {
        try {
            String routeName = route.toString ().trim ();
            JMSQueue jmsQueue = null;
            logger.info ("starting queue connection..."+routeName);            
            for (Iterator iter = inboundQueues.values ().iterator (); iter.hasNext ();) {
                jmsQueue = (JMSQueue) iter.next ();
                if (routeName.equalsIgnoreCase (jmsQueue.queueName)) {
                    jmsQueue.queueConnection.start ();
                }
            }
            logger.info ("queue connection "+routeName+" started");
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        } finally {
            
        }
    }
    
    /**
     * 
     * @param envelope
     * @return java.lang.Object
     * @throws gurulab.merlin.core.CantHandException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public Object handEnvelope (Envelope envelope) throws CantHandException {
        UVQueue queue;
        String layerId;
        try {
            layerId = envelope.getDestinationRoute ().getNode();
            if ((queue = (UVQueue) outboundQueues.get (layerId)) == null) {
                outboundQueues.put (layerId, queue = new JMSQueue (layerId));
            }
            
            queue.send (envelope);
            logger.info ("Envelope in the queue:" + envelope.getId ());
            if(envelope.getOrigin() instanceof PhoneAddress){
            	logger.info ("Origin:" + ((PhoneAddress)envelope.getOrigin()).getNumber());
            }
            if(envelope.getDestination() instanceof PhoneAddress){
            	logger.info ("Destination:" + ((PhoneAddress)envelope.getDestination()).getNumber());	
            }
        } catch (Exception e) {
            throw new CantHandException (e + "");
        } finally {
            
        }
        return envelope;
    }
    
    /**
     *
     * @param
     * @throws gurulab.merlin.bus.MessagingInfrastructureException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void finalize () throws MessagingInfrastructureException {
        try {
            for (Iterator iter = inboundQueues.values ().iterator (); iter.hasNext ();) {
                ((UVQueue) iter.next ()).finalize ();
            }
            
            for (Iterator iter = outboundQueues.values ().iterator (); iter.hasNext ();) {
                ((UVQueue) iter.next ()).finalize ();
            }
        } catch (Exception e) {
            throw new MessagingInfrastructureException (e + "");
        } finally {
            
        }
    }
    
    /**
     *
     * @param EnvelopeReference
     * @throws gurulab.merlin.core.CantHandException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */    
    public void retrieveEnvelope (Object EnvelopeReference) throws CantHandException {
    }
    
    /**
     * Hace persistente el procesamientos de un objeto Envelope.
     *
     * @param EnvelopeReference  Referencia al Envelope que fue procesado.
     * @throws gurulab.merlin.core.CantHandException
     * @author Cesar Obach-Renner, cesar AT gurulab.org
     */
    public void commitHandEnvelope (Object EnvelopeReference) throws CantHandException {
    }
    
}